All files / src/app/api/support/tickets/[id] route.ts

0% Statements 0/79
100% Branches 0/0
0% Functions 0/1
0% Lines 0/79

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80                                                                                                                                                               
export const dynamic = "force-dynamic";

/**
 * Support Ticket Detail API
 * GET /api/support/tickets/[id] - Get ticket details (customer view)
 */

import { NextRequest, NextResponse } from "next/server";
import { Session } from "next-auth";
import { prisma } from "@/lib/prisma";
import {
  withErrorHandling,
  withAuth,
  successResponse,
  ApiError } from "@/lib/api";
import { RouteContext } from "@/lib/api/middleware";

/**
 * GET /api/support/tickets/[id]
 * Get ticket details (customer can only view their own tickets)
 */
async function handleGet(
  _request: NextRequest,
  context: RouteContext | undefined,
  session: Session
): Promise<NextResponse> {
  if (!context?.params) {
    throw ApiError.invalidId("ticket");
  }

  const { id } = await context.params;
  const userId = Number(session.user.id);

  // Fetch the ticket
  const ticket = await prisma.supportTicket.findUnique({
    where: { id },
    include: {
      user: {
        select: { id: true, name: true, email: true } },
      order: {
        select: { id: true, status: true, total: true, createdAt: true } },
      product: {
        select: { id: true, title: true } },
      messages: {
        where: {
          isInternal: false, // Don't show internal messages to customers
        },
        include: {
          sender: {
            select: { id: true, name: true } },
          attachments: true },
        orderBy: { createdAt: "asc" } },
      attachments: true,
      survey: true,
      _count: {
        select: { messages: true } } } });

  if (!ticket) {
    throw ApiError.notFound("Ticket", id);
  }

  // Check ownership - customers can only view their own tickets
  if (ticket.userId !== userId) {
    throw ApiError.forbidden("Access denied");
  }

  // Mark unread messages as read
  await prisma.supportMessage.updateMany({
    where: {
      ticketId: id,
      senderType: { in: ["AGENT", "SYSTEM", "BOT"] },
      readAt: null },
    data: {
      readAt: new Date() } });

  return successResponse(ticket);
}

export const GET = withErrorHandling(withAuth(handleGet));